#pragma once

#include <memory>
#include <stdexcept>

#include "infer_config.h"
#include "session/session.h"
#include "utils/data/det_struct.h"

namespace infer {

/**
 * @class 模型推理基类模板
 * @brief 封装模型推理的推理逻辑,性能统计,结果处理等;使用不同类型的模型推理
 *        根据模板参数 R(Result) 区分不同类型的推理结果
 *        使用 utils/data/det_struct.h 中不同类型的结构体作为模板参数
 */
template<typename R>
class BaseModel {
public:
  BaseModel() = default;
  ~BaseModel() = default;

  /**
   * @brief 显式构造 BaseModel 对象
   *
   * @param engine_path txnn 编译后文件路径
   * @param cfg 推理配置的选项
   */
  explicit BaseModel(const std::string& engine_path, const InferConfig& cfg)
    : session_(std::make_unique<TxnnSession>(engine_path, cfg)) {
    // TODO 添加 timestamp 计时器
  }

  /**
   * @brief 对单张图像进行推理
   *
   * @param image 输入图像
   * @return 推理结果
   */
  R predict(const image::Image& image);

  /**
   * @brief 对多张图像进行推理
   *
   * @param image 输入图像列表
   * @return 推理结果列表
   */
  std::vector<R> predict(const std::vector<image::Image>& images);

protected:
  /**
   * @brief 后处理方法,根据模型类型不同,后处理逻辑不同
   *
   * @param idx 结果序号
   * @return 后处理的结果
   */
  R postProcess(int idx);

  std::unique_ptr<TxnnSession> session_;
};


#define INST_MODEL(R) template class BaseModel<R>; 
// 可以继续添加分割、位姿检测等CV类模型推理
INST_MODEL(det::ClassificationResult)
INST_MODEL(det::DetectionResult)
// 简洁地定义类型别名
using ClsModel = BaseModel<det::ClassificationResult>;
using DetModel = BaseModel<det::DetectionResult>;

} // namespace infer
